﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using CSA.Lib;

namespace CSA.Operator
{
    public class CloneOperator : ICSOperator
    {
        #region Fields

        private CSPopulation m_OperatePopulation=null;    
        String m_CurUsedFunctionName="";
        Hashtable m_FunctionNames = new Hashtable();    //Name-CSFunctionInfo

        #endregion  

        public CloneOperator()
        {
            InitialParameters();
        }

        ~CloneOperator()
        {           
        }

        #region Proerpties

        public Hashtable Get_Parameters(String nFunctionName)
        {
            String nValidateName="";
            if (nFunctionName.Trim() == "" || !m_FunctionNames.Contains(nFunctionName))
            {
                nValidateName = "DefaultCloneFunction";

            }
            else
            {
                nValidateName = nFunctionName;
            }
            CSFuntionInfo nDefulatParas = (CSFuntionInfo)m_FunctionNames[nValidateName];
            return nDefulatParas.Parameters;
        }

        public bool UseCustomAntibodyOperator
        {
            get { return false; }
        }

        public String Name
        {
            get
            {
                return "CloneOperator";
            }
        }

        public String Caption
        {
            get
            {
                return global::CSA.Operator.TextString.CloneOperatorCaption;
            }
        }

        public String Description
        {
            get
            {
                return global::CSA.Operator.TextString.CloneOperatorDes;
            }
        }

        public String Library
        {
            get
            {
                return "CSA.Operator";
            }
        }

        public OperatorType OperatorType
        {
            get
            {
                return OperatorType.enumClonalOperator;
            }
        }
        public Hashtable FunctionNames
        {
            get { return m_FunctionNames; }
        }

        public CSFuntionInfo CustomAntibodyOperator
        {
            get { return null; }
            set { }
        }

        #endregion   

        public bool Execute(CSPopulation nOperatePopulation, ref String nErrorStr, String nMethodName = "")
        {
            m_OperatePopulation = nOperatePopulation;
            if (nMethodName.Trim() == "" || !m_FunctionNames.Contains(nMethodName))
            {
                m_CurUsedFunctionName = "DefaultCloneFunction";
            }
            else
            {
                m_CurUsedFunctionName = nMethodName;
            }
            CSFuntionInfo nDefulatParas = (CSFuntionInfo)m_FunctionNames[m_CurUsedFunctionName];
            if (m_CurUsedFunctionName == "DefaultCloneFunction")
            {
                return Clone(ref nErrorStr);
            }
            return true;
        }

        public void InitialParameters()
        {
            m_FunctionNames.Clear();
            //Add the parameters of the default clonal function to the dictionary
            CSFuntionInfo nDefaultFunctionInfo = new CSFuntionInfo();
            nDefaultFunctionInfo.Caption = global::CSA.Operator.TextString.DefaultFunction;
            nDefaultFunctionInfo.Description = global::CSA.Operator.TextString.CloneOperatorDes;
            nDefaultFunctionInfo.Name = "DefaultCloneFunction";          
            float nDefaultClonalRate = 0.1F;  //
            Hashtable nStandardFunctionPara=new Hashtable();        

            CSParameter ClonalRate = new CSParameter();
            string nParaName2 = "CloneFactor";
            ClonalRate.Caption = global::CSA.Operator.TextString.CloneFactor;
            ClonalRate.Description = global::CSA.Operator.TextString.CloneFactorDes;
            ClonalRate.Name = nParaName2;
            ClonalRate.Value = nDefaultClonalRate;
            ClonalRate.Type = ParameterType.enumFloat;
            ClonalRate.DomainType = enumParasDomain.enumDomainExtent;
            string low2 = "0.01";
            string up2 = "10";
            List<string> nDomain2 = new List<string>();
            nDomain2.Add(low2);
            nDomain2.Add(up2);
            ClonalRate.DomainValues = nDomain2;
            nStandardFunctionPara.Add(nParaName2, ClonalRate);
            nDefaultFunctionInfo.Parameters = nStandardFunctionPara;
            m_FunctionNames.Add(nDefaultFunctionInfo.Name, nDefaultFunctionInfo);
        }

        private bool Clone(ref String nErrorStr)
        {
            try
            {
                CSFuntionInfo nDefulatParas = (CSFuntionInfo)m_FunctionNames[m_CurUsedFunctionName];
                CSParameter ClonalRate = (CSParameter)nDefulatParas.Parameters["CloneFactor"];
                Double nCloneFactor = Convert.ToDouble(ClonalRate.Value.ToString());
                int nPopSize;
                CSPopulation nPop = m_OperatePopulation;
                List<CSAntibody> nMemoryPop = nPop.MemoryAntibodies;
                List<CSAntibody> nNonMemoryPop = nPop.Antibodies;
                List<CSAntibody> nNewPop = nPop.NewAntibodies;
                List<int> nCloneCount = new List<int>();
                int nTotal = 0;
                nNewPop.Sort(new AntibodyCompare());
                nPopSize = nMemoryPop.Count + nNonMemoryPop.Count;
                for (int i = 0; i < nNewPop.Count; i++)
                {
                    double nCloneNumber = (nCloneFactor) * nPopSize;
                    int nCloneNum = (int)Math.Round(nCloneNumber);
                    nCloneCount.Add(nCloneNum);
                    nTotal += nCloneNum;
                }
                //Loop，Clone
                Int32 nCurCopyAntibody;
                int nCurCopyIndex = 0;
                for (nCurCopyAntibody = 0; nCurCopyAntibody != nNewPop.Count; ++nCurCopyAntibody)
                {
                    if (nCurCopyIndex == (int)(nCloneCount.Count))
                    {
                        break;
                    }
                    if (nCloneCount[nCurCopyIndex] > 0)
                    {
                        CSAntibody nCurAnti = nNewPop[nCurCopyAntibody];
                        for (int t = 0; t < nCloneCount[nCurCopyIndex] - 1; t++)
                        {
                            CSAntibody nCurCopyAnti = (CSAntibody)nCurAnti.Clone();
                            nNewPop.Add(nCurCopyAnti);
                        }
                    }
                    else
                    {
                        break;
                    }
                    nCurCopyIndex++;
                }
                //Sort
                nNewPop.Sort(new AntibodyCompare());
                return true;
            }
            catch(Exception ex)
            {
                nErrorStr = ex.Message;
                return false;
            }
        }
    }
}
